from __future__ import with_statement
from khronos import *
from khronos.extras.components import *

class Machine(Atomic):
    state = TSeriesAttr(storing=True, numeric=False, timescale=DAY)
    
    @chain
    def initializer(self):
        Machine.state.initialize(self, "SB")
        job = 0
        rng = self.get_rng()
        fail = self.launch(Thread(self.next_failure(), name="fail"))
        
        while self.get_timedelta() < WEEK:
            self.state = "PR"
            with self.broadcasting("job %d" % (job,)):
                evt = Delay(rng.gauss(15.0, 1.0) * MINUTE)
                yield evt
                while evt.canceled():
                    with self.broadcasting("repairs"):
                        self.state = "UDR"
                        yield rng.gauss(5.0, 0.2) * MINUTE
                    evt = Delay(evt.remaining)
                    fail = self.launch(Thread(self.next_failure(), name="fail"))
                    self.state = "PR"
                    yield evt
            job +=1
            self.state = "SB"
            with fail.paused():
                yield rng.uniform(0.5, 5.0) * MINUTE
        fail.terminate()
        
    @chain
    def next_failure(self):
        yield max(0, self.get_rng().expovariate(1.0 / 1.5)) * HOUR
        self.cancel()
        
    def finalizer(self):
        plt = Plotter("Machines example: %s" % (self,))
        state = Machine.state.stat(self)
        state.run_chart(plotter=plt)
        state.bar_chart(plotter=plt)
        state.pareto_chart(plotter=plt)
        state.pie_chart(plotter=plt)
        
def build_model():
    m = Composite("machines")
    for x in xrange(2):
        Machine("mach#%d" % (x,), m)
    return m
    
def build():
    k = Khronos()
    k.attach(build_model())
    return k, k.model

k, m = build()
main = build_model
